package com.sdhs.paas.gateway.filter;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;

import javax.validation.constraints.NotNull;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;

import com.alibaba.fastjson.JSONObject;
import com.sdhs.paas.authshare.common.msg.AccessForbiddenResponse;
import com.sdhs.paas.authshare.common.msg.BaseResponse;
import com.sdhs.paas.authshare.context.BaseContextHandler;
import com.sdhs.paas.gateway.config.AcmanageRuleConfig;
import com.sdhs.paas.gateway.constant.AmeConstant;
import com.sdhs.paas.gateway.model.AmeAccessPolicy;
import com.sdhs.paas.gateway.util.PaasAccessUtil;
import com.sdhs.paas.gateway.util.RequestUtils;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Configuration
public class AdminAccessFilter implements GlobalFilter {

	@Autowired
	private AcmanageRuleConfig acmanageRuleConfig;

	@Override
	public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
		ServerHttpRequest request = serverWebExchange.getRequest();
		ServerHttpRequest.Builder mutate = request.mutate();
		String token = BaseContextHandler.getToken();
		// 获取用户id
		String userId = RequestUtils.getAccountName(request);
		if (userId == null) {
			ServerHttpRequest build = mutate.build();
			return gatewayFilterChain.filter(serverWebExchange.mutate().request(build).build());
		}

		// 获取请求路径
		String requestPath = request.getPath().pathWithinApplication().value();
		String method = request.getMethod().toString();
		// 根据请求路径获取访问策略
		AmeAccessPolicy ameAccessPolicy = getAmeAccessPolicy(requestPath,method);
		//判断默认是否允许访问
	    boolean isAccess = this.acmanageRuleConfig.isDefaultAccessAllowed();
	    if(isAccess){
	    	ServerHttpRequest build = mutate.build();
			return gatewayFilterChain.filter(serverWebExchange.mutate().request(build).build());
	    }
	    //如果根据请求路径可以获取访问策略
	    if (ameAccessPolicy != null) {
	    	isAccess = PaasAccessUtil.hasPolicy(userId, ameAccessPolicy.getResource(), ameAccessPolicy.getAction());
	    }
	    //如果没有权限，就返回403，拒绝访问
	    if (!isAccess) {
	    	return getVoidMono(serverWebExchange,new AccessForbiddenResponse("access was denied"));
//          String body = "access was denied";
//          serverWebExchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
//          byte[] bytes = JSONObject.toJSONString(body).getBytes(StandardCharsets.UTF_8);
//          DataBuffer buffer = serverWebExchange.getResponse().bufferFactory().wrap(bytes);
//          return serverWebExchange.getResponse().writeWith(Flux.just(buffer));
	    }
		ServerHttpRequest build = mutate.build();
		return gatewayFilterChain.filter(serverWebExchange.mutate().request(build).build());
	}

	private AmeAccessPolicy getAmeAccessPolicy(String requestPath,String method) {
		List<AmeAccessPolicy> accessPolicyList = getAccessRules();

		HashMap generalMap = new HashMap();
		List<AmeAccessPolicy> regexList = new ArrayList();
		for (AmeAccessPolicy accessPolicy : accessPolicyList) {
			if (accessPolicy.getRequestPath().contains("{*}"))
				regexList.add(accessPolicy);
			else {
				generalMap.put(accessPolicy.toString(), accessPolicy);
			}
		}

		AmeAccessPolicy queryAccessPolicy = new AmeAccessPolicy(requestPath, method);
		if (generalMap.containsKey(queryAccessPolicy.toString())) {
			return (AmeAccessPolicy) generalMap.get(queryAccessPolicy.toString());
		}
		for (AmeAccessPolicy accessPolicy : regexList) {
			if (accessPolicy.getRequestMethod().matches(method)) {
				String pattern = accessPolicy.getRequestPath().replace("{*}", "[\\w\\d\\.-]+");
				if (Pattern.matches(pattern, requestPath)) {
					return accessPolicy;
				}
			}
		}
		return null;
	}

	private List<AmeAccessPolicy> getAccessRules() {
		List accessPolicyList = new ArrayList();
		List<List<String>> accessRules = this.acmanageRuleConfig.getAccessRules();
		for (List rule : accessRules)
			if (rule.size() == AmeConstant.NumberEnum.FOUR.ordinal()) {
				AmeAccessPolicy accessPolicy = new AmeAccessPolicy((String) rule.get(0),
						HttpMethod.resolve(((String) rule.get(1)).toUpperCase()), (String) rule.get(2),
						(String) rule.get(3));

				accessPolicyList.add(accessPolicy);
			}
		return accessPolicyList;
	}
	
	/**
     * 网关抛异常
     *
     * @param body
     */
    @NotNull
    private Mono<Void> getVoidMono(ServerWebExchange serverWebExchange, BaseResponse body) {
        serverWebExchange.getResponse().setStatusCode(HttpStatus.OK);
        byte[] bytes = JSONObject.toJSONString(body).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = serverWebExchange.getResponse().bufferFactory().wrap(bytes);
        return serverWebExchange.getResponse().writeWith(Flux.just(buffer));
    }
	
}
